//
//  AppDelegate.m
//  testTrezord
//
//  Created by Mac on 2024/7/12.
//

#import "AppDelegate.h"
#include <stdlib.h>
#include <string.h>
#import "HexConverter.h"
#include <unistd.h>
#import <Security/Security.h>

#import <Foundation/Foundation.h>
#import "MessagesManagement.pbobjc.h"
#import "MessagesEthereum.pbobjc.h"
#import "MessagesBitcoin.pbobjc.h"
#import "MessagesCommon.pbobjc.h"
#import "NetworkCenter.h"
#import "NetworkManager.h"

const NSString * deviceNotFound = @"NODEVICEFOUND";

@interface AppDelegate ()
@property (strong) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
    [self startAcecssTrezorDevice];
}


- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}


- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
    return YES;
}


- (void)startAcecssTrezorDevice {
    sleep(4);
    //[self createWalletWhole];
    //[self wipeDevice];
    //[self getAddress];
    //[self getPublicKey];

    [self recoveryWallet];
    //    [self checkBridgeVersion];
    //[self UnlockBootloader: @"6"];
    //[self pollDeviceStatus];
    // create wallet
    //[[NetworkCenter sharedInstance] createWallet:Type_Create_Wallet];
    // Recovery wallet
    //[[NetworkCenter sharedInstance] recoveryWallet:Type_Recovery_Wallet];
    
}


+ (NSData *)dataFromHexString:(NSString *)hexString {
    NSMutableData *data = [NSMutableData data];
    for (int i = 0; i < hexString.length; i += 2) {
        NSString *hexByte = [hexString substringWithRange:NSMakeRange(i, 2)];
        uint8_t byte = (uint8_t)strtoul([hexByte UTF8String], NULL, 16);
        [data appendBytes:&byte length:1];
    }
    return data;
}
- (BOOL)isObjectNull:(id)object {
    return [object isKindOfClass:[NSNull class]];
}

- (NSString *) getSessionId{
    [self checkBridgeVersion];
    NSString * path = nil;
    NSString * oldSession = nil;
    
    NSArray *jsonResponse = [self enumerateDevices];
    
    if (jsonResponse.count > 0) {
        path = jsonResponse[0][@"path"];
        oldSession = jsonResponse[0][@"session"];
        
        
        if ([self isObjectNull:oldSession]) {
            oldSession = @"null";
        }
        else
            return oldSession;
        
        
    } else {
        NSLog(@"No devices found.");
        return deviceNotFound;//here, we click the device screen or input pin
    }
    
    NSString * session =  [self acquireDeviceWithPath:path oldSession:oldSession];
    
    return session;
    
}


- (void ) recoveryWallet{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    [self getFeaturesWithSession:session];
    [self releaseSession:session];
    
    session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;

    [self initializeTrezorDevice:session];
    [self sendRecoveryCommandWithSession:session];
    [self getFeaturesWithSession:session];
//     get status to check whether pin nit set
    //[self sendRestartCommandWithSession:session];
    [self releaseSession:session];
    
    session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;

    [self initializeTrezorDevice0:session];
    if([self isDeviceRecovered:session])
    {
        NSLog(@"Wallet recovered");
        
    }else
        NSLog(@"recovery failed:");
        
    [self getTestCoinAddress:session];
//    [self sendRestartCommandWithSession:session];
    [self releaseSession:session];

    //[self sendButtonAckCommandWithSession:session];
    //[self sendRestartCommandWithSession:session];
    
}

- (void ) getAddress{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    
    [self initializeTrezorDevice:session];
    //[self getTestCoinAddress:session];
    //[self getTestCoinAddress:session];
    [self getBitCoinAddress:session];
    [self getEthernumAddress:session];
    
    [self releaseSession:session];

}


- (void ) getPublicKey{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    

    //[self getTestCoinAddress:session];
    //[self getTestCoinAddress:session];
    [self getBitCoinPublicKey:session];
    [self getEthernumAddress:session];
    
    [self releaseSession:session];

}

- (void ) createWallet{
    [self createWallet0];
    //[self createWallet1];
    //[self createWallet2];
}

- (void ) createWalletWhole{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    [self getFeaturesWithSession:session];
    [self releaseSession:session];
    
    session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;

    [self initializeTrezorDevice:session];
    [self sendResetDeviceCommandWithSession:session];
    [self getFeaturesWithSession:session];
    
    [self releaseSession:session];
    
    session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;

    [self initializeTrezorDevice0:session];
    if([self isDeviceRecovered:session])
    {
        NSLog(@"Wallet recovered");
        
    }else
        NSLog(@"recovery failed:");
        
    [self getTestCoinAddress:session];
//    [self sendRestartCommandWithSession:session];
    [self releaseSession:session];

    //[self sendButtonAckCommandWithSession:session];
    
}

- (void ) wipeDevice {
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    
    [self WipeDeviceWithSession:session];
    [self sendRestartCommandWithSession:session];
    
    [self releaseSession:session];

    
    
}


- (void ) createWallet0{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    
    //init device
    [self initializeTrezorDevice:session];
    [self sendResetDeviceCommandWithSession:session];
    [self getTestCoinAddress:session];
//    [self sendRestartCommandWithSession:session];
    [self releaseSession:session];

    
}

- (void ) createWallet1{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    
    //init device
    //[self initializeTrezorDevice:session];
    [self getFeaturesWithSessionForCheckBackup:session];
       // [self startBackupDeviceCommandWithSession:session];
    [self releaseSession:session];

    
}

- (void ) createWallet2{
    
    NSString * session =  [self getSessionId];
    if([session isEqualToString:deviceNotFound])
        return;
    
    
    //init device
    //[self initializeTrezorDevice:session];
    [self getFeaturesWithSessionForPin:session];
    ////[self startChangePin:session];
    [self getTestCoinAddress:session];
    
    if([self isDeviceRecovered:session])
    {
        NSLog(@"Wallet created");
        
    }else
        NSLog(@"creating failed:");
    [self sendRestartCommandWithSession:session];
    
    [self releaseSession:session];

    //[self sendButtonAckCommandWithSession:session];
    
}


- (void )checkBridgeVersion {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/"];
    NSURL *url = [NSURL URLWithString:urlString];
    
    
    [NetworkCenter getMessageResponse: nil url: url];
}

- (NSArray * )enumerateDevices {
        
        NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/enumerate"];
        NSURL *url = [NSURL URLWithString:urlString];
  
        NSData *data = [NetworkCenter getMessageResponse: nil url: url];
        
        NSArray *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
        NSLog(@"Enumerate Response: %@", jsonResponse);
        
        return jsonResponse;
    }

- (NSString * )acquireDeviceWithPath:(NSString *)path oldSession:(NSString *)oldSession {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/acquire/%@/%@", path, oldSession];
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSData *data = [NetworkCenter getMessageResponse: nil url: url];


    NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"Acquire Response: %@", jsonResponse);
    
    NSString *newSession = jsonResponse[@"session"];
    
    if (newSession != nil) {
        return newSession;
    } else {
        NSLog(@"No devices found.");
    }
    return nil;

}


//for test get address only
- (void )acquireDeviceWithPath2:(NSString *)session0 {
        NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/acquire/1/%@", session0];
        NSURL *url = [NSURL URLWithString:urlString];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
        [request setHTTPMethod:@"POST"];

    NSURLSession *session = [NSURLSession sharedSession];
        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error acquiring device: %@", error.localizedDescription);
        }
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSLog(@"Acquire Response: %@", jsonResponse);
            //[self sendRecoveryCommandWithSession:newSession];
            
            //[self getDeviceStatusWithSession:newSession];
            //[self getFeaturesWithSession:newSession];
            //            [self startRecoveryWithSession:newSession mnemonicLength:12];
            //[self sendInitializeCommandWithSession: newSession];
            //  create wallet
            //            [self sendResetDeviceCommandWithSession:newSession];
            //[self getFeaturesWithSessionForCreate:newSession];
            //[self getFeaturesWithSessionForPin:newSession];
            NSString *newSession = jsonResponse[@"session"];
            
            //[self getEthernumAddress:newSession];
            //[self getBitCoinAddress:newSession];
            [self initializeTrezorDevice: newSession];
            
        } else {
            NSLog(@"Failed to acquire device. Status code: %ld", (long)httpResponse.statusCode);
        }
    }];
    
    [dataTask resume];
}
- (void )sendRecoveryCommandWithSession:(NSString *)session0
{
    NSString *mnemonics = @"fat doll attend father upgrade destroy cement magic humor axis wait logic";
    NSInteger mnemonicsCount = 12;
    

    RecoveryDevice *recoveryDevice = [[RecoveryDevice alloc] init];
    //recoveryDevice.hasWordCount = NO;
    recoveryDevice.wordCount = mnemonicsCount;  // Set according to your backup phrase length
    //recoveryDevice.hasPassphraseProtection = YES;
    recoveryDevice.passphraseProtection = YES;  // Set based on user's original configuration
    //recoveryDevice.hasPinProtection = YES;
    recoveryDevice.pinProtection = YES;  // Set based on user's original configuration
    //recoveryDevice.hasLanguage = YES;
    recoveryDevice.language = @"english";  // Deprecated but set if necessary
   //recoveryDevice.hasLabel = YES;
    recoveryDevice.label = @"My Trezor";  // Optional: Set a label for the device
    recoveryDevice.enforceWordlist = YES;  // Enforce the standard BIP39 wordlist
    recoveryDevice.dryRun = NO;  // Ensure it's a real recovery, not a test
    
    NSMutableDictionary *dictWordsPassphrasePin = [[NSMutableDictionary alloc]init];
    NSString *passphrase=@"";
    //NSString *passphrase=@"Qianlue";
    NSString *pin=@"202407";
    NSError * err;
 
    [dictWordsPassphrasePin setValue: @"My Trezor" forKey:@"label"];
    [dictWordsPassphrasePin setValue: pin forKey:@"pin"];
    [dictWordsPassphrasePin setValue: passphrase  forKey:@"passphrase"];
    [dictWordsPassphrasePin setValue: mnemonics forKey:@"words"];

    NSData * jsonData = [NSJSONSerialization dataWithJSONObject:dictWordsPassphrasePin options:0 error:&err];
    NSString *string0 = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
   
    // Convert NSString to NSData
    NSData *data0 = [string0 dataUsingEncoding:NSUTF8StringEncoding];

    // Encode NSData to Base64 NSString
    NSString *extendedLanguage = [data0 base64EncodedStringWithOptions:0];
    recoveryDevice.label = extendedLanguage;  // Deprecated but set if necessary
   
    NSString *cmdType = @"002d";
    NSData *serializedData = [recoveryDevice data];
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",cmdType,len / 2,hexStringBodyData]];

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Recovery Command Response DATA: %@", data);
            
      NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw BtnACK Response String: %@", responseString); // This will show the exact content of the response
    //NSString *substring = [responseString substringFromIndex:12];



    [self handleDeviceResponseString:responseString session: session0];

}

- (NSString * )sendButtonAckCommandWithSession:(NSString *)session0 {
    
    NSString *hexString = @"001b00000000";
    //NSData *bodyData = [HexConverter dataFromHexString:hexString];
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    
    
    
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Post ButtonAck Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw BtnACK Response String: %@", responseString); // This will show the exact content of the response
            //NSString *substring = [responseString substringFromIndex:12];
            NSData *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSLog(@"ButtonAck Command Response: %@", responseData);
            return [self handleDeviceResponseString:responseString session: session0];
}

-(NSData *)generateSecureRandomData:(NSInteger )length{
    NSMutableData *randomData = [[NSMutableData alloc] initWithLength:length];
    if (SecRandomCopyBytes(kSecRandomDefault, length, randomData.mutableBytes) != errSecSuccess) {
        NSLog(@"Error generating secure random bytes");
        return nil;
    }
    return randomData;
}


- (NSString *)sendEntropyAckCommandWithSession:(NSString *)session0 {
    NSString *hexString = @"0024"; // Replace with the actual recovery command
    
    EntropyAck *entropyAck = [[EntropyAck alloc] init];
    NSData *entropyData = [self generateSecureRandomData: 32];
    [entropyAck setEntropy:entropyData];
    NSData *serializedData = [entropyAck data];
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
            NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
            return [self handleDeviceResponseString: responseString session: session0];
}

- (void)listenDeviceWithPath:(NSString *)path session:(NSString *)session0 {
    
    
    NSNumber *product = @0;
    NSNumber *vendor = @0;
    NSNumber *debug = @NO; // Corrected to boolean
    NSString *debugSession = @"null";
    
    NSDictionary *parameters = @{@"path": path,
                                 @"session": session0,
                                 @"product": product,
                                 @"vendor": vendor,
                                 @"debug": debug,
                                 @"debugSession": debugSession};
    NSArray *parametersArray = @[parameters];
    
    NSError *jsonError;
    NSData *bodyData = [NSJSONSerialization dataWithJSONObject:parametersArray options:0 error:&jsonError];
    
    [NetworkCenter listenDeviceWithPathWithBody:bodyData completion:^(NSData *data, NSError *error, NSURLResponse *response) {
        if (error) {
            NSLog(@"Error listening to device: %@", error.localizedDescription);
            return;
        }
        
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            NSArray *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSLog(@"Listen Response: %@", jsonResponse);
            
            // Process the response and determine the next action
            //            [self handleDeviceResponse:jsonResponse];
            //            [self listenDeviceWithPath:jsonResponse[0][@"path"] session:session0];
            [self sendRestartCommandWithSession:session0];
        } else {
            NSLog(@"Failed to listen to device. Status code: %ld", (long)httpResponse.statusCode);
            NSLog(@"Response: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }
    }];
}

- (void)handleDeviceResponse:(NSArray *)responseArray {
    // Iterate over the response array and handle each entry
    for (NSDictionary *response in responseArray) {
        NSString *messageType = response[@"type"];
        
        if ([messageType isEqualToString:@"ButtonRequest"]) {
            // Send ButtonAck again if needed
            //[self sendButtonAckCommandWithSession:session0];
            [self sendButtonAckCommandWithSession:response[@"session"]];
        } else if ([messageType isEqualToString:@"PinMatrixRequest"]) {
            // Handle PinMatrixRequest
            // Prompt the user to enter the PIN and send it using a similar method
        } else if ([messageType isEqualToString:@"PassphraseRequest"]) {
            // Handle PassphraseRequest
            // Prompt the user to enter the passphrase and send it using a similar method
        } else if ([messageType isEqualToString:@"Success"]) {
            // Handle Success
            NSLog(@"Recovery process successful: %@", response);
        } else if ([messageType isEqualToString:@"Failure"]) {
            // Handle Failure
            NSLog(@"Recovery process failed: %@", response);
        } else {
            // Handle other types of messages
            NSLog(@"Unhandled response type: %@", messageType);
        }
    }
}

- (NSString *)handleDeviceResponseString:(NSString *)response session:(NSString *) session  {
    NSString *messageType = [response substringToIndex:4];
    if ([messageType isEqualToString:@"0002"]) {
        NSString *substring = [response substringFromIndex:12];
        NSData *data = [HexConverter dataFromHexString:substring];
        NSError *parseError = nil;
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

        return result;
    }else if ([messageType isEqualToString:@"0023"]) {
        return [self sendEntropyAckCommandWithSession:session];
    } else if ([messageType isEqualToString:@"001a"]) {
        // Send ButtonAck again if needed
       return  [self sendButtonAckCommandWithSession:session];
    } else if ([messageType isEqualToString:@"0012"]) {
        [self sendPinMatrixAckWithSession:session pin: @"202407"];
        return nil;
    }else if ([messageType isEqualToString:@"0029"]) {
        
       return [self  sendPassphraseAckWithSession:session passphrase:@""];

    } else if ([messageType isEqualToString:@"0003"]) {
        // Handle Failure
        NSLog(@"Recovery process failed: %@", response);
        return response;
    } else  {
        // Handle other types of messages
        NSLog(@"Unhandled response type: %@", messageType);
        return response;
    }
}


- (void)sendRestartCommandWithSession:(NSString *)session0 {
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"005700000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
    //NSLog(@"Restart Command Response DATA: %@", data0);
//    NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//    NSLog(@"Restart Command Response: %@", responseData);
}

- (void)getDeviceStatusWithSession:(NSString *)session0 {
    
    // [self getFeaturesWithSession: session0];
    
    NSString *hexString = @"003700000000"; // GetFeatures command
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    [NetworkCenter getDeviceStatusWithSessionWithBody:bodyData session:session0 completion:^(NSData *data, NSError *error, NSURLResponse *response) {
        if (error) {
            NSLog(@"Error sending GetFeatures command: %@", error.localizedDescription);
            return;
        }
        
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            NSString *string0 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            // NSData *data1 = [TrezorViewController dataFromHexString:string0];
            // NSString *string1 = [[NSString alloc] initWithData:data1 encoding:NSUTF8StringEncoding];
            //  NSLog(@"GetFeatures Command Response: %@", string1);
            
            //  NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:string1 options:0 error:nil];
            //NSLog(@"GetFeatures Command Response: %@", responseData);
            
            // Process the features to determine the device status
            //[self processDeviceStatus:responseData];
        } else {
            NSLog(@"Failed to send GetFeatures command. Status code: %ld", (long)httpResponse.statusCode);
        }
    }];
}

//- (void)getFeaturesWithSession:(NSString *)session0 {
//
//    NSString *hexString = @"003700000000"; // Example, replace with actual command
//    //NSData *bodyData = [TrezorViewController dataFromHexString:hexString];
//    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
//    [NetworkCenter getFeaturesWithSessionWithBody:bodyData session:session0 completion:^(NSData *data, NSError *error, NSURLResponse *response) {
//        if (error) {
//            NSLog(@"Error sending GetFeatures command: %@", error.localizedDescription);
//            return;
//        }
//
//        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//        if (httpResponse.statusCode == 200) {
//            NSLog(@"GetFeatures Response DATA: %@", data);
//            NSError *error;
//            Features *message = [Features parseFromData:data error:&error];
//
//            NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//            NSLog(@"GetFeatures Response: %@",string);
//            NSData *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//            NSLog(@"GetFeatures Response: %@", responseData);
//            [self sendRecoveryCommandWithSession:session0];
//        } else {
//            NSLog(@"Failed to send GetFeatures command. Status code: %ld", (long)httpResponse.statusCode);
//        }
//    }];
//}

- (Features *)getFeaturesWithSession:(NSString *)session0 {
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"003700000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
    
     NSLog(@"Raw Response String: %@", data); // This will show the exact content of the response

    
    
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
                NSString *substring = [responseString substringFromIndex:12];
                NSData *featuresData = [HexConverter dataFromHexString:substring];
                NSError *parseError = nil;
                Features *features = [Features parseFromData:featuresData error:&parseError];
                if (parseError) {
                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
                } else {
                    NSLog(@"Received Features: %@", features);
                    return features;
                }
    
    return nil;
    }
    

- (void)getFeaturesWithSessionForCreate:(NSString *)session0 {
    NSString *hexString = @"003700000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    [NetworkCenter getFeaturesWithSessionWithBody:bodyData session:session0 completion:^(NSData *data, NSError *error, NSURLResponse *response) {
        if (!error) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
                NSString *substring = [responseString substringFromIndex:12];
                NSData *featuresData = [HexConverter dataFromHexString:substring];
                NSError *parseError = nil;
                Features *features = [Features parseFromData:featuresData error:&parseError];
                if (parseError) {
                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
                } else {
                    NSLog(@"Received Features: %@", features);
                    [self startBackupDeviceCommandWithSession:session0];
                }
            }
        } else {
            NSLog(@"Error sending PIN: %@", error.localizedDescription);
        }
    }];
    //    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    //    NSURL *url = [NSURL URLWithString:urlString];
    //    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //    [request setHTTPMethod:@"POST"];
    //    [request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];
    //    [request setHTTPBody:bodyData];
    //    NSURLSession *session = [NSURLSession sharedSession];
    //    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //        if (!error) {
    //            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    //            if (httpResponse.statusCode == 200) {
    //                NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    //                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
    //                NSString *substring = [responseString substringFromIndex:12];
    //                NSData *featuresData = [HexConverter dataFromHexString:substring];
    //                NSError *parseError = nil;
    //                Features *features = [Features parseFromData:featuresData error:&parseError];
    //                if (parseError) {
    //                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
    //                } else {
    //                    NSLog(@"Received Features: %@", features);
    //                    [self startBackupDeviceCommandWithSession:session0];
    //                }
    //            }
    //        } else {
    //            NSLog(@"Error sending PIN: %@", error.localizedDescription);
    //        }
    //    }];
    //    [dataTask resume];
}

- (void)getFeaturesWithSessionForPin:(NSString *)session0 {
    Features *features = [self getFeaturesWithSessionForBackUp:session0];
    if (features) {
        if (features.hasPinProtection && !features.pinProtection) {
            NSLog(@"PIN protection is enabled on the device.");
            [self startChangePin:session0];
        } else {
            NSLog(@"PIN protection is not enabled on the device.");
        }
    }
}



- (Features *)getFeaturesWithSessionForBackUp:(NSString *)session0 {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"0000000000021800";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
    
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
    NSString *substring = [responseString substringFromIndex:12];
    NSData *featuresData = [HexConverter dataFromHexString:substring];
    NSError *parseError = nil;
    Features *features = [Features parseFromData:featuresData error:&parseError];
    if (parseError) {
        NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
    } else {
        NSLog(@"Received Features: %@", features);
        return features;
    }
    
    return nil;
    
}
- (void)getFeaturesWithSessionForCheckBackup:(NSString *)session0 {
    Features *features = [self getFeaturesWithSessionForBackUp:session0];
    if (features) {
        if (features.needsBackup) {
            [self startBackupDeviceCommandWithSession:session0];
        }
    }
    
}

- (BOOL)isDeviceRecovered:(NSString *)session0 {
    Features *features = [self getFeaturesWithSession:session0];
    if (features) {
        return [self isDeviceReady:features];
        
    }
    
    return FALSE;
}



- (void)sendInitializeCommandWithSession:(NSString *)session0
{
    [self sendResetDeviceCommandWithSession:session0];
}

- (NSString *)sendResetDeviceCommandWithSession:(NSString *)session0
{
    NSInteger mnemonicsCount = 12;

    ResetDevice *resetDevice = [[ResetDevice alloc] init];
    resetDevice.displayRandom = NO;  // Ensure it's a real recovery, not a test
    resetDevice.strength = 128;  // Set according to your backup phrase length
    resetDevice.passphraseProtection = YES;  // Set based on user's original configuration
    resetDevice.pinProtection = YES;  // Set based on user's original configuration
    resetDevice.language = @"english";  // Deprecated but set if necessary
    resetDevice.label = @"My Trezor";  // Optional: Set a label for the device
    resetDevice.noBackup = NO;
    resetDevice.skipBackup = NO;
    resetDevice.hasU2FCounter = NO;
    resetDevice.backupType = BackupType_Bip39;
    
    NSMutableDictionary *dictWordsPassphrasePin = [[NSMutableDictionary alloc]init];
    NSString *passphrase=@"";
//    NSString *passphrase=@"Qianlue";
    NSString *pin=@"202407";
    NSError * err;
    
    [dictWordsPassphrasePin setValue: @"My Trezor" forKey:@"label"];
    [dictWordsPassphrasePin setValue: pin forKey:@"pin"];
    [dictWordsPassphrasePin setValue: passphrase  forKey:@"passphrase"];
    
    EntropyAck *entropyAck = [[EntropyAck alloc] init];
    NSData *entropyData = [self generateSecureRandomData: 32];
    [entropyAck setEntropy:entropyData];
    NSData *serializedData0 = [entropyAck data];
    NSString *hexStringBodyData0 = [HexConverter hexStringFromData: serializedData0];
    [dictWordsPassphrasePin setValue: hexStringBodyData0  forKey:@"entropyAck"];
    
    NSData * jsonData = [NSJSONSerialization dataWithJSONObject:dictWordsPassphrasePin options:0 error:&err];
    NSString *string0 = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
   
    // Convert NSString to NSData
    NSData *data0 = [string0 dataUsingEncoding:NSUTF8StringEncoding];

    // Encode NSData to Base64 NSString
    NSString *extendedLabel = [data0 base64EncodedStringWithOptions:0];
    resetDevice.label = extendedLabel;  // Deprecated but set if necessary
   
    
    NSString *cmdType = @"000e";
    NSData *serializedData = [resetDevice data];
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",cmdType,len / 2,hexStringBodyData]];

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"ResetDevice Response String: %@", responseString); // This will show the exact content of the response
    NSLog(@"ResetDevice Command Response: %@", responseString);
    return [self handleDeviceResponseString:responseString session: session0];
}

- (void)processDeviceStatus:(NSDictionary *)features {
    BOOL initialized = [features[@"initialized"] boolValue];
    BOOL bootloaderMode = [features[@"bootloader_mode"] boolValue];
    if (bootloaderMode) {
        NSLog(@"Device is in bootloader mode.");
    } else if (initialized) {
        NSLog(@"Device is initialized.");
    } else {
        NSLog(@"Device is uninitialized.");
    }
}

-(void)startRecoveryWithSession:(NSString *)session0 mnemonicLength:(NSInteger)length {
    
    NSString *hexString = [NSString stringWithFormat:@"<Hex code for RecoveryDevice with length %ld>", (long)length]; // Placeholder
    NSData *bodyData = [HexConverter dataFromHexString:hexString];
    [NetworkCenter startRecoveryWithSessionWithBody:bodyData session:session0 completion:^(NSData *data, NSError *error, NSURLResponse *response) {
        if (error) {
            NSLog(@"Error starting recovery: %@", error.localizedDescription);
            return;
        }
        
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSLog(@"Recovery started: %@", responseData);
            [self handleWordRequestWithData:responseData session:[NSURLSession sharedSession]];
        } else {
            NSLog(@"Failed to start recovery. Status code: %ld", (long)httpResponse.statusCode);
        }
    }];
}

- (NSString *) getWordAtIndex:(NSInteger) index {
    NSArray *mnemonic = @[@"fat",@"doll",@"attend",@"father",@"upgrade",@"destroy",@"cement",@"magic",@"humor",@"axis",@"wait",@"logic"];
    
    return mnemonic[index];
}

- (void)handleWordRequestWithData:(NSDictionary *)data session:(NSURLSession *)session {
    NSString *responseType = data[@"type"];
    if ([responseType isEqualToString:@"WordRequest"]) {
        NSInteger wordIndex = [data[@"wordPos"] integerValue];  // Assuming the API gives the position
        NSString *nextWord = [self getWordAtIndex:wordIndex];    // Fetch the word from your stored mnemonic
        
        [self sendWord:nextWord session:session];
    }
}

- (void)sendWord:(NSString *)word session:(NSURLSession *)session {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    
    NSString *hexString = [NSString stringWithFormat:@"<Hex code for WordAck with word '%@'>", word]; // Placeholder
    NSData *bodyData = [HexConverter dataFromHexString:hexString];
    [request setHTTPBody:bodyData];
    
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error sending word: %@", error.localizedDescription);
            return;
        }
        
        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
            NSLog(@"Word sent successfully: %@", responseData);
            // Check if more words are needed or if recovery is complete
        } else {
            NSLog(@"Failed to send word. Status code: %ld", (long)httpResponse.statusCode);
        }
    }];
    
    [dataTask resume];
}

- (void)startBackupDeviceCommandWithSession:(NSString *)session0 {
    
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"002200000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
            
            //NSString *substring = [responseData substringFromIndex:12];
            
            
            // Handle the response, possibly send ButtonAck
            [self handleDeviceResponseString:responseString session: session0];
}

- (void) startChangePin:(NSString *)session0
{
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"0004000000020800";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
            //NSString *substring = [responseData substringFromIndex:12];
            // Handle the response, possibly send ButtonAck
            [self handleDeviceResponseString:responseString session: session0];
            
}

- (BOOL)isDeviceReady:(Features *)features {
    if (!features.initialized) {
        NSLog(@"Device is not initialized.");
        return NO;
    }
    if (features.needsBackup) {
        NSLog(@"Device needs backup.");
        return NO;
    }
    if (features.pinProtection) {
        NSLog(@"PIN protection is enabled.");
        // Add logic to handle PIN entry if your application manages that flow
    }
    if (features.passphraseProtection) {
        NSLog(@"Passphrase protection is enabled.");
        // Add logic to handle passphrase entry if your application manages that flow
    }
//    if (!features.firmwarePresent) {
//        NSLog(@"Firmware is not present.");
//        return NO;
//    }
    NSLog(@"Device is ready to work.");
    return YES;
}


- (void)processFeatures:(NSData *)data {
    NSError *error = nil;
    Features *features = [Features parseFromData:data error:&error];
    if (error) {
        NSLog(@"Error parsing Features: %@", error.localizedDescription);
        return;
    }
    BOOL deviceReady = [self isDeviceReady:features];
    if (deviceReady) {
        // Proceed with wallet operations
        NSLog(@"Device is ready for wallet operations.");
    } else {
        // Handle not ready state, possibly by prompting user actions or showing error messages
        NSLog(@"Device is not ready for operations. Further user action required.");
    }
}


- (void )WipeDeviceWithSession:(NSString *)session0 {
    
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"000500000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

//            NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  //          NSLog(@"Word sent successfully: %@", responseData);
    
}


//- (NSData *)createEthereumAddressRequest {
//    EthereumGetAddress *request = [[EthereumGetAddress alloc] init];
////    [request setAddressNArray:[NSMutableArray arrayWithArray:@[@2147483692, @2147483708, @2147483648, @0, @0]]];
//    [request setAddressNArray:[NSMutableArray arrayWithArray:@[@2147483692, @2147483708, @2147483648, @0, @0]]];
//
//    request.showDisplay = YES;
//
//    NSError *error = nil;
//    NSData *data = [request data];
//    if (error) {
//        NSLog(@"Failed to serialize request: %@", error);
//        return nil;
//    }
//
//    return data;
//}
//
//- (void )getEthernumAddress:(NSString *)session0 {
//
//    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
//    NSURL *url = [NSURL URLWithString:urlString];
//    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//    [request setHTTPMethod:@"POST"];
//
//    NSString *hexString = @"0038"; // Replace with the actual recovery command
//
//    NSData *serializedData = [self createEthereumAddressRequest2];
//    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
//
//    NSInteger len = [hexStringBodyData length];
//    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
//    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
//    //bodyData = serializedData;
//    [request setHTTPBody:bodyData];
//    NSURLSession *session = [NSURLSession sharedSession];
//
//    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//        if (error) {
//            NSLog(@"Error sending getEthernumAddress command: %@", error.localizedDescription);
//        }
//        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//        if (httpResponse.statusCode == 200) {
//            NSLog(@"Post getEthernumAddress Command Response DATA: %@", data);
//            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//            NSLog(@"Raw getEthernumAddress Response String: %@", responseString); // This will show the exact content of the response
//            NSString *substring = [responseString substringFromIndex:12];
//
//
//            //NSData *responseData = [NSJSONSerialization JSONObjectWithData:substring options:0 error:nil];
//            NSData *responseData = [HexConverter dataFromHexString:substring];
//            NSLog(@"getEthernumAddress Command Response: %@", responseData);
//            NSError *error = nil;
//            EthereumAddress * ea = [EthereumAddress parseFromData:responseData error:&error];
//            NSLog(@"getEthernumAddress returned address: %@", ea);
//            //[self listenDeviceWithPath:@"1" session:session0];
//            //[self startBackupDeviceCommandWithSession:session0];
//            //[self sendRestartCommandWithSession:session0];
//            //[self getFeaturesWithSessionForCreate:session0];
//
//
//        } else {
//            NSLog(@"Failed to send ButtonAck command. Status code: %ld", (long)httpResponse.statusCode);
//            //            [self listenDeviceWithPath:@"1" session:session1];
//        }
//    }];
//
//
//    [dataTask resume];
//}

- (NSData *)createCoinAddressRequestWithCoinType:(uint32_t)coinType
                                      accountNum:(uint32_t)accountNum
                                    addressIndex:(uint32_t)addressIndex
                                        coinName:(NSString *)coinName
{
    NSData *data = nil;
    
    if([coinName isEqualTo:@"Bitcoin"]) {
        uint32_t values[] = {0x8000002c, coinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

        GetAddress *getAddress =  [[GetAddress alloc] init];
        getAddress.addressNArray = addressNArray;
        getAddress.coinName = coinName;
        //getAddress.scriptType = 0; // Ensure this is set correctly if needed
        getAddress.showDisplay = YES;
        data = [getAddress data];
    }else if([coinName isEqualTo:@"Ethereum"]){
        uint32_t values[] = {0x8000002c, coinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

        EthereumGetAddress *getAddressEth = [[EthereumGetAddress alloc] init];
        getAddressEth.addressNArray = addressNArray;
        NSString *networkString = @"mainnet";
        NSData *networkData = [networkString dataUsingEncoding:NSUTF8StringEncoding];

        getAddressEth.encodedNetwork = networkData;
        //[getAddressEth ]
        //getAddressEth.coinName = coinName;
        getAddressEth.showDisplay = YES; // Depending on your needs for UI feedback
        data = [getAddressEth data];
    }

    if (data) {
        NSLog(@"Serialization successful, data length: %lu", (unsigned long)[data length]);
    } else {
        NSLog(@"Error serializing GetAddress");
    }
    return data;
}

- (void )getBitCoinAddress:(NSString *)session0 {
    uint32_t bitcoinType = 0x80000000; // Bitcoin type for Ethereum
    uint32_t accountNum = 0x80000000; // The no. 0 account
    uint32_t addressIndex = 0; // The no. 0 address index, can be 1, 2, 3
    NSString *bitcoinName = @"Bitcoin"; // Assuming this was meant to be bitcoinName/coinName

    [self getCoinAddress:session0 bitcoinType:bitcoinType accountNum:accountNum addressIndex:addressIndex  coinName:bitcoinName];
    
}

- (void )
getEthernumAddress:(NSString *)session0 {
    uint32_t coinType = 0x8000003c; // SLIP-44 coin type for Ethereum
    uint32_t accountNum = 0x80000000; // Account number
    uint32_t addressIndex = 0; // Address index
    NSString *coinName = @"Ethereum"; // Coin name should match the expected value by the API

    [self getCoinAddress:session0 bitcoinType:coinType accountNum:accountNum addressIndex:addressIndex coinName:coinName];
    
}

- (void )getCoinAddress:(NSString *)session0
            bitcoinType:(uint32_t)bitcoinType
             accountNum:(uint32_t)accountNum
           addressIndex:(uint32_t)addressIndex
               coinName:(NSString *) coinName
{
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

//    NSString *hexString = @"001d"; // Replace with the actual recovery command
    NSString *hexString = @"0038"; // Replace with the actual recovery command
    NSData *serializedData = [self createCoinAddressRequestWithCoinType:bitcoinType accountNum:accountNum addressIndex:addressIndex coinName:coinName];
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
    //hexStringSent = @"001d0000002108ac80808008088180808008088080808008080008001207546573746e65742800";
    NSLog(@"getCoinAddress command is: %@", hexStringSent);

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
            [self handleDeviceResponseString: responseString session: session0];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
    
    NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
    responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response

//            NSCharacterSet *hexCharacterSet = [NSCharacterSet characterSetWithCharactersInString:responseString];
//    
//    // //NSData *responseData = [NSJSONSerialization JSONObjectWithData:substring options:0 error:nil];
//                NSString * addressString = [responseString substringFromIndex:12];
//             //   NSData *responseData = [HexConverter dataFromHexString:addressString];
//             //   NSLog(@"getAddress Command Response: %@", responseData);
//             //   NSError *error = nil;
//              //  Address * ads = [Address parseFromData:responseData error:&error];
//             //   NSLog(@"getAddress returned address: %@", ads);
//
//    NSLog(@"getAddress returned addres end......");
            
            
}

    
- (void )getTestCoinAddress:(NSString *)session0
{
    NSString * hexStringSent = @"001d0000002108ac80808008088180808008088080808008080008001207546573746e65742800";

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
    NSString * address = [self handleDeviceResponseString: responseString session: session0];
    NSLog(@"Address is: %@", address);
    
    NSString *substring = [responseString substringFromIndex:12];
    NSData *addressData = [HexConverter dataFromHexString:substring];
    NSError *parseError = nil;
    Address * ea = [Address parseFromData:addressData error:&parseError];
    if (parseError) {
        NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
    } else {
        NSLog(@"Received Features: %@", ea);
        
    }


    
}

- (NSString * )sendPinMatrixAckWithSession:(NSString *)session0 pin:(NSString *)pin {
    NSString *hexString = @"0013"; // Replace with the actual recovery command
    PinMatrixAck * pma = [[PinMatrixAck alloc] init];
    [pma setPin:pin];
    //[pma setHasPin:TRUE];
    
    NSError *error = nil;
    NSData *serializedData = [pma data];
    if (error) {
        NSLog(@"Failed to serialize request: %@", error);
        return nil;
    }
    
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
            NSLog(@"Post getEthernumAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getEthernumAddress Response String: %@", responseString); // This will show the exact content of the response
            NSString *substring = [responseString substringFromIndex:12];
            
            //NSData *responseData = [NSJSONSerialization JSONObjectWithData:substring options:0 error:nil];
            NSData *responseData = [HexConverter dataFromHexString:substring];
            NSLog(@"getEthernumAddress Command Response: %@", responseData);
    return [self handleDeviceResponseString: responseString session: session0];

}


- (NSString *)sendPassphraseAckWithSession:(NSString *)session0 passphrase:(NSString *)passphrase {
    NSString *hexString = @"002a"; // Replace with the actual recovery command
    PassphraseAck * ppa = [[PassphraseAck alloc] init];
    [ppa setPassphrase:passphrase];
    //[ppa hasPassphrase:TRUE];
    
    NSError *error = nil;
    NSData *serializedData = [ppa data];
    if (error) {
        NSLog(@"Failed to serialize request: %@", error);
        return nil;
    }
    
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
    //hexStringSent = @"002a000000020a00";
    NSLog(@"Webpage Passphrase command is: %@", @"002a000000020a00");
    NSLog(@"Passphrase command is: %@", hexStringSent);
    
    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];
    NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
    return [self handleDeviceResponseString: responseString session: session0];

}


//- (void)sendPassphraseAckWithSession:(NSString *)session0 passphrase:(NSString *)passphrase {
//    NSString *hexString = @"002a"; // Replace with the actual recovery command
//    PassphraseAck * ppa = [[PassphraseAck alloc] init];
//    [ppa setPassphrase:passphrase];
//    //[ppa hasPassphrase:TRUE];
//    
//    NSError *error = nil;
//    NSData *serializedData = [ppa data];
//    if (error) {
//        NSLog(@"Failed to serialize request: %@", error);
//        return ;
//    }
//    
//    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
//    
//    NSInteger len = [hexStringBodyData length];
//    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];
//    //hexStringSent = @"002a000000020a00";
//    NSLog(@"Webpage Passphrase command is: %@", @"002a000000020a00");
//    NSLog(@"Passphrase command is: %@", hexStringSent);
//    
//    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
//    
//    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
//    NSURL *url = [NSURL URLWithString:urlString];
//    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//    [request setHTTPMethod:@"POST"];
//    [request setTimeoutInterval:30.0];
//    [request setValue:@"*/*" forHTTPHeaderField:@"Accept"];
//    [request setValue:@"gzip, deflate, br, zstd" forHTTPHeaderField:@"Accept-Encoding"];
//    [request setValue:@"zh-CN,zh;q=0.9" forHTTPHeaderField:@"Accept-Language"];
//    [request setValue:@"keep-alive" forHTTPHeaderField:@"Connection"];
//    [request setValue:@"text/plain;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
//    [request setValue:@"127.0.0.1:21325" forHTTPHeaderField:@"Host"];
//    [request setValue:@"https://suite.trezor.io" forHTTPHeaderField:@"Origin"];
//    [request setValue:@"empty" forHTTPHeaderField:@"Sec-Fetch-Dest"];
//    [request setValue:@"cors" forHTTPHeaderField:@"Sec-Fetch-Mode"];
//    [request setValue:@"cross-site" forHTTPHeaderField:@"Sec-Fetch-Site"];
//    [request setValue:@"trezor client" forHTTPHeaderField:@"User-Agent"];
//    [request setValue:@"\"Not/A)Brand\";v=\"8\", \"Chromium\";v=\"126\", \"Google Chrome\";v=\"126\"" forHTTPHeaderField:@"sec-ch-ua"];
//    [request setValue:@"?0" forHTTPHeaderField:@"sec-ch-ua-mobile"];
//    [request setValue:@"\"macOS\"" forHTTPHeaderField:@"sec-ch-ua-platform"];
//
//    
//        [request setHTTPBody:bodyData];
//        NSURLSession *session = [NSURLSession sharedSession];
//    
//    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//        if (error) {
//            NSLog(@"Error sending getEthernumAddress command: %@", error.localizedDescription);
//        }
//        else {
//            NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
////            if ([responseDict[@"error"] isEqualToString:@"device disconnected during action"]) {
//            NSString *value = responseDict[@"error"];
//            if (value && [value isKindOfClass:[NSString class]] && [value length] > 0) {
//                NSLog(@"Error.... Trying again...");
////                [self performSelector:@selector(sendPassphraseAckWithSession:passphrase:) withObject:session withObject:passphrase afterDelay:2.0];
//                [self performSelector:@selector(sendPassphraseAckWithSession:passphrase:) withObject:passphrase];
//            } else {
//                NSLog(@"Passphrase accepted by device.");
//            }
//        }
//        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//        if (httpResponse.statusCode == 200) {
//            NSLog(@"Post sendPassphraseAckWithSession Command Response DATA: %@", data);
//            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//            NSLog(@"Raw sendPassphraseAckWithSession Response String: %@", responseString); // This will show the exact content of the response
//            NSString *substring = [responseString substringFromIndex:12];
//            
//            
//            
//            //NSData *responseData = [NSJSONSerialization JSONObjectWithData:substring options:0 error:nil];
//            NSData *responseData = [HexConverter dataFromHexString:substring];
//            NSLog(@"getAddress Command Response: %@", responseData);
//            NSError *error = nil;
//            //EthereumAddress * ea = [EthereumAddress parseFromData:responseData error:&error];
//            Address * ea = [Address parseFromData:responseData error:&error];
//            NSLog(@"getAddress returned address: %@", [ea address]);
//            [self releaseSession: session0];
//
//            //[self getFeaturesWithSessionForCreate:session0];
////            uint32_t bitcoinTYpe = @2147483708;//0x8000003c 66 ethernum
////            uint32_t accountNum = @2147483648;//0x80000000 the no 0 aacount
////            uint32_t addressIndex = 0;// the num 0 address index, can be 1, 2,3
//            
//           // [self getCoinAddress:session0 bitcoinType:bitcoinTYpe accountNum:accountNum addressIndex:addressIndex];
//
//            
//            
//        } else {
//            NSLog(@"Failed to send sendPassphraseAckWithSession command. Status code: %ld", (long)httpResponse.statusCode);
//            NSLog(@"Post sendPassphraseAckWithSession Command Response DATA: %@", data);
//            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
//            NSLog(@"Raw sendPassphraseAckWithSession Response String: %@", responseString); // This will show the exact content of the response
//            //            [self listenDeviceWithPath:@"1" session:session1];
//            [self releaseSession: session0];
//            //[self checkBridgeVersion];
//            //[self acquireDeviceWithPath2: session0];
//            
//            //[self performSelector:@selector(sendPassphraseAckWithSession:passphrase:) withObject:passphrase];
//
//        }
//        //[self releaseSession: session0];
//    }];
//    
//    [dataTask resume];
//
//}


- (NSString *)promptUserForPassphrase {
    // Securely prompt the user to enter their passphrase
    // Return the passphrase entered by the user
    return @"UserEnteredPassphrase";
}

- (void)sendPassphraseAckWithPassphrase:(NSString *)passphrase forSession:(NSString *)session {
    // Construct the command to send the PassphraseAck back to the device
    // Similar to previous example provided for sending PassphraseAck
}
// TODO:
//    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
//    NSURL *url = [NSURL URLWithString:urlString];
//    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//    [request setHTTPMethod:@"POST"];
//
//    NSString *hexString = @"000e0000001a108001180132094d79205472657a6f7238b7ad9eb40640015000"; // ResetDevice command
//    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
//    //NSData *bodyData = [HexConverter dataFromHexString:hexString];
//    [request setHTTPBody:bodyData];
//
//    NSURLSession *session1 = [NSURLSession sharedSession];
//    NSURLSessionDataTask *dataTask = [session1 dataTaskWithRequest:request completionHandler:^(NSData *data0, NSURLResponse *response, NSError *error) {
//        if (error) {
//            NSLog(@"Error sending ResetDevice command: %@", error.localizedDescription);
//            return;
//        }
//
//        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//        if (httpResponse.statusCode == 200) {
//            NSDictionary *responseData = [NSJSONSerialization JSONObjectWithData:data0 options:0 error:nil];
//            NSLog(@"ResetDevice Command Response: %@", responseData);
//
//            // Handle the response, possibly send ButtonAck
//            //[self handleDeviceResponse:responseData];
//            [self sendButtonAckCommandWithSession:session0];
//        } else {
//            NSLog(@"Failed to send ResetDevice command. Status code: %ld", (long)httpResponse.statusCode);
//        }
//    }];
//
//    [dataTask resume];

- (void)getFeaturesWithSessionForAddress:(NSString *)session0 {
    NSString *hexString = @"003700000000";
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];
    [NetworkCenter getFeaturesWithSessionWithBody:bodyData session:session0 completion:^(NSData *data, NSError *error, NSURLResponse *response) {
        if (!error) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
                NSString *substring = [responseString substringFromIndex:12];
                NSData *featuresData = [HexConverter dataFromHexString:substring];
                NSError *parseError = nil;
                Features *features = [Features parseFromData:featuresData error:&parseError];
                if (parseError) {
                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
                } else {
                    NSLog(@"Received Features: %@", features);
                    [self sendPassphraseAckWithSession:session0 passphrase: @""];
                    //[self startBackupDeviceCommandWithSession:session0];
                }
            }
        } else {
            NSLog(@"Error sending PIN: %@", error.localizedDescription);
        }
    }];
}

- (void)listenForMessagesFromDeviceWithSession:(NSString *)session0 {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];

    PassphraseRequest * ppr = [[PassphraseRequest alloc] init];
    [ppr setOnDevice:FALSE];
    
    NSError *error = nil;
    NSData *serializedData = [ppr data];
    if (error) {
        NSLog(@"Failed to serialize request: %@", error);
        return ;
    }
    
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];

    // The request body should be configured according to what you're listening for
    // For example, for Trezor, you may continuously poll or listen for a specific endpoint
    // Here, you might be sending a command to listen, or checking the device's state

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error receiving data from device: %@", error.localizedDescription);
        } else {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                NSLog(@"Successfully received data from device.");
                // Process the data here, decide if it's the message type you're waiting for
                [self processDeviceMessage:data];
            } else {
                NSLog(@"Failed to receive valid response from device. Status code: %ld", (long)httpResponse.statusCode);
            }
        }
    }];
    
    [dataTask resume]; // Start listening
}

- (void)processDeviceMessage:(NSData *)data {
    NSLog(@"PprocessDeviceMessage DATA: %@", data);
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"processDeviceMessage String: %@", responseString); // This will show the exact content of the response
    NSString *substring = [responseString substringFromIndex:12];
    NSData *responseData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
    NSLog(@"processDeviceMessage Response: %@", responseData);
    [self handleDeviceResponseString:responseString session: @"1"];

}


- (void)checkForPassphraseRequestWithSession:(NSString *)session0 {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];

    // Send a specific command or just check status to provoke/passively listen for a PassphraseRequest
    // The body should be set according to what command you're issuing that might result in a PassphraseRequest
    // For demonstration, let's assume it's a generic "get status" or similar
    NSString *commandString = @"{\"command\": \"get status\"}"; // Replace with actual command if needed
    NSData *commandData = [commandString dataUsingEncoding:NSUTF8StringEncoding];
    [request setHTTPBody:commandData];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error receiving data from device: %@", error.localizedDescription);
        } else {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                [self processReceivedData:data];
            } else {
                NSLog(@"Failed to receive valid response from device. Status code: %ld", (long)httpResponse.statusCode);
            }
        }
    }];
    
    [dataTask resume]; // Start the task
}

- (void)processReceivedData:(NSData *)data {
    NSError *error;
    NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
    if (error) {
        NSLog(@"Error parsing JSON from device response: %@", error.localizedDescription);
        return;
    }
    
    // Check for a PassphraseRequest in the response
    if ([responseDict[@"message_type"] isEqualToString:@"PassphraseRequest"]) {
        NSLog(@"PassphraseRequest received.");
        // Handle passphrase request here
        [self handlePassphraseRequest];
    } else {
        NSLog(@"Received message: %@", responseDict);
    }
}

- (void)handlePassphraseRequest {
    // Code to handle passphrase input and send PassphraseAck
}
- (void)pollDeviceStatus {
    NSString *urlString = @"http://127.0.0.1:21325/listen";
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    // Empty body or minimal JSON as per actual API requirements
    [request setHTTPBody:[@"[]" dataUsingEncoding:NSUTF8StringEncoding]];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error polling device: %@", error.localizedDescription);
            if ([error.localizedDescription containsString:@"EOF"]) {
                NSLog(@"EOF received. Attempting to reconnect...");
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [self pollDeviceStatus];  // Attempt to reconnect after a delay
                });
            }
        } else {
            //[self handleDeviceResponse:data];
            [self handleDeviceResponseWhenDebugPassphrase:data];
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self pollDeviceStatus];  // Continue polling if no error
            });
        }
    }];

    [dataTask resume];
}
- (void)handleDeviceResponseWhenDebugPassphrase:(NSData *)data {
    NSError *error;
    NSDictionary *responseDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
    
    if (error) {
        NSLog(@"Error parsing device response: %@", error.localizedDescription);
        return;
    }
    
    NSLog(@"Polled Event response: %@", responseDict);
    if(responseDict != nil)
        return;
    
    // Example of handling a hypothetical passphrase request
    NSObject * nso0 = responseDict[@"needs_passphrase"];
    NSObject * nso1 = responseDict[@"needs_pin"];
    NSObject * nso2 = responseDict[@"not_connected"];
    
    if (nso0 != nil && [responseDict[@"needs_passphrase"] boolValue]) {
        NSString *session = responseDict[@"session"];
        //NSString *passphrase = [self promptUserForPassphrase];
        //[self sendPinMatrixAckWithSession:session pin: @"12"];
        
        //[self sendPinMatrixAckWithSession:@"12" pin:e forSession:session];
        [self sendPassphraseAckWithSession:session passphrase: @""];
    }else if (nso1 != nil &&  [responseDict[@""] boolValue]) {
        NSString *session = responseDict[@"session"];
        //NSString *passphrase = [self promptUserForPassphrase];
        [self sendPinMatrixAckWithSession:session pin: @"12"];
        
        //[self sendPinMatrixAckWithSession:@"12" pin:e forSession:session];
    //    [self sendPassphraseAckWithPassphrase:passphrase forSession:session];
    }else if (nso2 != nil && [responseDict[@""] boolValue]) {
        NSString *session = responseDict[@"session"];
        //NSString *passphrase = [self promptUserForPassphrase];
        [self sendPinMatrixAckWithSession:session pin: @"12"];
        
        //[self sendPinMatrixAckWithSession:@"12" pin:e forSession:session];
    //    [self sendPassphraseAckWithPassphrase:passphrase forSession:session];
    }
}


- (void)initializeTrezorDevice0:(NSString *)session0 {
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    //NSString *hexString = @"0000000000021800";
    NSString *hexString = @"000000000000";
    
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

                NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
                NSString *substring = [responseString substringFromIndex:12];
                NSData *featuresData = [HexConverter dataFromHexString:substring];
                NSError *parseError = nil;
                Features *features = [Features parseFromData:featuresData error:&parseError];
                if (parseError) {
                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
                } else {
                    NSLog(@"Received Features: %@", features);
                }
}

- (void)initializeTrezorDevice:(NSString *)session0 {
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSString *hexString = @"0000000000021800";
    //NSString *hexString = @"000000000000";
    
    NSData *bodyData = [hexString dataUsingEncoding:NSUTF8StringEncoding];

    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

                NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSLog(@"Raw Response String: %@", responseString); // This will show the exact content of the response
                NSString *substring = [responseString substringFromIndex:12];
                NSData *featuresData = [HexConverter dataFromHexString:substring];
                NSError *parseError = nil;
                Features *features = [Features parseFromData:featuresData error:&parseError];
                if (parseError) {
                    NSLog(@"Failed to parse features: %@", parseError.localizedDescription);
                } else {
                    NSLog(@"Received Features: %@", features);
                }
}


- (void)releaseSession:(NSString *)session0 {
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/release/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];
    
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error polling device: %@", error.localizedDescription);
           
        } else {
            NSLog(@"session released: %@", session0);
        }
    }];

    [dataTask resume];
}



- (void)UnlockBootloader:(NSString *)session0 {
    [self getFeaturesWithSession:session0];
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"POST"];

    //UnlockBootloader * ubl = [[UnlockBootloader alloc] init];
    NSString *hexString = @"006000000000";

        
    //NSString *hexStringBodyData = [HexConverter hexStringFromData: hexString];
    [request setHTTPBody:hexString];
    // The request body should be configured according to what you're listening for
    // For example, for Trezor, you may continuously poll or listen for a specific endpoint
    // Here, you might be sending a command to listen, or checking the device's state

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"Error receiving data from device: %@", error.localizedDescription);
        } else {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200) {
                NSLog(@"Successfully received data from device.");
                // Process the data here, decide if it's the message type you're waiting for
                [self processDeviceMessage:data];
            } else {
                NSLog(@"Failed to receive valid response from device. Status code: %ld", (long)httpResponse.statusCode);
            }
        }
    }];
    
    [dataTask resume]; // Start listening
}



- (void )getBitCoinPublicKey:(NSString *)session0 {
    uint32_t bitcoinType = 0x80000000; // Bitcoin type for Ethereum
    uint32_t accountNum = 0x80000000; // The no. 0 account
    uint32_t addressIndex = 0; // The no. 0 address index, can be 1, 2, 3
    NSString *bitcoinName = @"Bitcoin"; // Assuming this was meant to be bitcoinName/coinName
    
    
    
    NSData *data = nil;
    
        uint32_t values[] = {0x8000002c, bitcoinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

    GetPublicKey *getPublicKey =  [[GetPublicKey alloc] init];
    getPublicKey.addressNArray = addressNArray;
//    getPublicKey.coinName = coinName;
        //getAddress.scriptType = 0; // Ensure this is set correctly if needed
    getPublicKey.showDisplay = YES;
        data = [getPublicKey data];

    
    if (data) {
        NSLog(@"Serialization successful, data length: %lu", (unsigned long)[data length]);
    } else {
        NSLog(@"Error serializing GetAddress");
    }


    [self getCoinPublicKey:session0 CommandType:@"000b" CommandData:data];
    
}

- (void )getEthernumPublicKey:(NSString *)session0 {
    uint32_t coinType = 0x8000003c; // SLIP-44 coin type for Ethereum
    uint32_t accountNum = 0x80000000; // Account number
    uint32_t addressIndex = 0; // Address index
    NSString *coinName = @"Ethereum"; // Coin name should match the expected value by the API
    NSData *data = nil;
    
        uint32_t values[] = {0x8000002c, coinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

        EthereumGetPublicKey *getPK = [[EthereumGetPublicKey alloc] init];
        getPK.addressNArray = addressNArray;
//        NSString *networkString = @"mainnet";
//        NSData *networkData = [networkString dataUsingEncoding:NSUTF8StringEncoding];
//    
//
//    getPK. = networkData;
        //[getAddressEth ]
        //getAddressEth.coinName = coinName;
        getPK.showDisplay = YES; // Depending on your needs for UI feedback
        data = [getPK data];

    if (data) {
        NSLog(@"Serialization successful, data length: %lu", (unsigned long)[data length]);
    } else {
        NSLog(@"Error serializing GetAddress");
    }
    
    [self getCoinPublicKey:session0 CommandType:@"01c2" CommandData:data];

}



- (void )getCoinPublicKey:(NSString *)session0 CommandType: (NSString *)cmdType CommandData: (NSData *) cmdData
{
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

    NSString *hexString = cmdType;
    NSData *serializedData = cmdData;
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
            [self handleDeviceResponseString: responseString session: session0];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
    
    NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
    responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
}


- (void )signBitCoinTx:(NSString *)session0 {
    uint32_t bitcoinType = 0x80000000; // Bitcoin type for Ethereum
    uint32_t accountNum = 0x80000000; // The no. 0 account
    uint32_t addressIndex = 0; // The no. 0 address index, can be 1, 2, 3
    NSString *bitcoinName = @"Bitcoin"; // Assuming this was meant to be bitcoinName/coinName
    
    
    
    NSData *data = nil;
    
        uint32_t values[] = {0x8000002c, bitcoinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

    GetPublicKey *getPublicKey =  [[GetPublicKey alloc] init];
    getPublicKey.addressNArray = addressNArray;
//    getPublicKey.coinName = coinName;
        //getAddress.scriptType = 0; // Ensure this is set correctly if needed
    getPublicKey.showDisplay = YES;
        data = [getPublicKey data];

    
    if (data) {
        NSLog(@"Serialization successful, data length: %lu", (unsigned long)[data length]);
    } else {
        NSLog(@"Error serializing GetAddress");
    }


    [self getCoinPublicKey:session0 CommandType:@"000b" CommandData:data];
    
}

- (void )signEthernumTx:(NSString *)session0 {
    uint32_t coinType = 0x8000003c; // SLIP-44 coin type for Ethereum
    uint32_t accountNum = 0x80000000; // Account number
    uint32_t addressIndex = 0; // Address index
    NSString *coinName = @"Ethereum"; // Coin name should match the expected value by the API
    NSData *data = nil;
    
        uint32_t values[] = {0x8000002c, coinType, accountNum, 0, addressIndex};
        GPBUInt32Array *addressNArray = [[GPBUInt32Array alloc] initWithValues:values count:5];

        EthereumSignTx *esTx = [[EthereumSignTx alloc] init];
        esTx.addressNArray = addressNArray;
//        NSString *networkString = @"mainnet";
//        NSData *networkData = [networkString dataUsingEncoding:NSUTF8StringEncoding];
//
//
//    getPK. = networkData;
        //[getAddressEth ]
        //getAddressEth.coinName = coinName;
//        getPK.showDisplay = YES; // Depending on your needs for UI feedback
        data = [esTx data];

    if (data) {
        NSLog(@"Serialization successful, data length: %lu", (unsigned long)[data length]);
    } else {
        NSLog(@"Error serializing GetAddress");
    }
    
    [self getCoinPublicKey:session0 CommandType:@"01c2" CommandData:data];

}



- (void )signTx:(NSString *)session0 CommandType: (NSString *)cmdType CommandData: (NSData *) cmdData
{
    
    NSString *urlString = [NSString stringWithFormat:@"http://127.0.0.1:21325/call/%@", session0];
    NSURL *url = [NSURL URLWithString:urlString];

    NSString *hexString = cmdType;
    NSData *serializedData = cmdData;
    NSString *hexStringBodyData = [HexConverter hexStringFromData: serializedData];
    
    NSInteger len = [hexStringBodyData length];
    NSString *hexStringSent = [[NSString alloc] initWithString:[NSString stringWithFormat:@"%@%08x%@",hexString,len / 2,hexStringBodyData]];

    NSData *bodyData = [hexStringSent dataUsingEncoding:NSUTF8StringEncoding];
    
    
    NSData *data = [NetworkCenter getMessageResponse: bodyData url: url];

            NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
            NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
            [self handleDeviceResponseString: responseString session: session0];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
    
    NSLog(@"Post getCoinAddress Command Response DATA: %@", data);
    responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Raw getCoinAddress Response String: %@", responseString); // This will show the exact content of the response
}


/***
the recovery process:
1,checkBridgeVersion 查看是否活着
2，enumerateDevices 枚举设备 我们这儿只返回path 1 表示第一个设备
3，acquireDeviceWithPath 获得设备控制权， 加独占锁
4，sendRecoveryCommandWithSession 发送恢复指令。
5，sendButtonAckCommandWithSession 发送确认按钮，在班子上展示绿色要求确认按钮
6，sendRestartCommandWithSession 发送重启指令
7，getDeviceStatusWithSession
8，processDeviceStatus
 
 the Create process:
 1,checkBridgeVersion 查看是否活着
 2，enumerateDevices 枚举设备 我们这儿只返回path 1 表示第一个设备
 3，acquireDeviceWithPath 获得设备控制权， 加独占锁
 4，sendResetDeviceCommandWithSession 。
 if reponse code is buttonRequest then 5 else error
 5， sendButtonAckCommandWithSession
 if reponse code is EntropyRequest then 6 else error
 6 sendEntropy ack
 
 if reponse is initialized or getFeature is_initialized = true and needs_backup then 7 else error
 here, can directly call backup process
 7，sendBackup
 
 
 8,  getFeature can be omitted in create wallet
 9,  startBackupDeviceCommandWithSessionWithBody
 
   backup指令  002200000000
 
 success: return 0002
 
 10,  getFeatureForPin: to decide wether need set pin,  can be omitted in create wallet
 11,  startChangePin
 发送buttonAck
  返回PinMatrixRequest
 你发送PinMatrixAck
 ......
 
 你自己试试
 
 
 ***/

@end


